#include "plot_controller.h"

PlotController::PlotController(QCustomPlot *plot,
    QObject *parent)
    : QObject{parent}
    , m_plot {plot}
{
    assert(plot != nullptr);
    m_plot->installEventFilter(this);
}

PlotController::~PlotController()
{
    m_plot = nullptr;
}

bool PlotController::eventFilter(QObject *watched, QEvent *event)
{
    if(watched == m_plot) {
        if(!m_tracerEnabled)
            return false;
        if(event->type() == QEvent::MouseMove) {
            if (m_plot->graphCount() == 0) return false;
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            // 获取鼠标位置并转换为坐标值
            double x_val = m_plot->xAxis->pixelToCoord(mouseEvent->pos().x());
            double y_val = m_plot->yAxis->pixelToCoord(mouseEvent->pos().y());

            // 判断是否在曲线附近（容差范围可调）
            double tolerance = 20*20;
            bool found = false;
            const QCPGraphData *selectData = nullptr;
            double diff;
            for(int i = 0; i < m_plot->graphCount(); i++) {
                int index = m_plot->graph(i)->findBegin(x_val, true); // 查找最近数据点索引
                const QCPGraphData *data = m_plot->graph(i)->data()->at(index);
                double x = m_plot->xAxis->coordToPixel(data->key);
                double y = m_plot->yAxis->coordToPixel(data->value);
                double tmp = (mouseEvent->pos().x()-x)*(mouseEvent->pos().x()-x) + (mouseEvent->pos().y()-y)*(mouseEvent->pos().y()-y);
                if (tmp < tolerance) {
                    if(!selectData) {
                        diff = tmp;
                        selectData = data;
                    }
                    else {
                        if(tmp < diff) {
                            diff = tmp;
                            selectData = data;
                        }
                    }
                }
            }
            if(selectData) {
                auto getString = [=](QCPAxis *axis, double value) {
                    QCPAxisTickerDateTime *tickerDateTime = dynamic_cast<QCPAxisTickerDateTime *>(axis->ticker().data());
                    if(tickerDateTime)
                        return QCPAxisTickerDateTime::keyToDateTime(value).toString("hh:mm:ss");
                    QCPAxisTickerTime *tickerTime = dynamic_cast<QCPAxisTickerTime *>(axis->ticker().data());
                    if(tickerTime) {
                        const int MsOfDay = 24*60*60*1000;
                        int days = (int64_t)value / MsOfDay;
                        QString s;
                        if(days > 0) {
                            s = QString("%1d ").arg(days);
                        }
                        s += QTime::fromMSecsSinceStartOfDay((int64_t)value % MsOfDay).toString("hh:mm:ss");
                        return s;
                    }
                    return QString::number(value);
                };
                QToolTip::showText(mouseEvent->globalPos(),
                                   QString("(%1, %2)")
                                       .arg(getString(m_plot->xAxis, selectData->key))
                                       .arg(getString(m_plot->yAxis, selectData->value)),
                                   m_plot);
            } else {
                QToolTip::hideText();
            }
            return false;
        }
        else
            return false;
    }
    else
        return parent()->eventFilter(watched, event);
}

int PlotController::addGraph(const QString &name)
{
    QCPGraph *graph = m_plot->addGraph();
    if(graph) {
        if(!name.isEmpty())
            graph->setName(name);
        return m_plot->graphCount()-1;
    }
    return -1;
}

void PlotController::addData(int graphIndex, double key, double value)
{
    if(graph(graphIndex))
        graph(graphIndex)->addData(key, value);
}

void PlotController::setBackground(const QBrush &background)
{
    m_plot->setBackground(background);
}

void PlotController::setAxisRectBackground(const QBrush &background)
{
    m_plot->axisRect()->setBackground(background);
}

void PlotController::replot(QCustomPlot::RefreshPriority refreshPriority)
{
    m_plot->replot(refreshPriority);
}

void PlotController::setGridPen(int index, const QPen &pen)
{
    QCPAxis *pAxis = this->axis(index);
    if(pAxis) {
        pAxis->grid()->setPen(pen);
    }
}

void PlotController::setSubGridPen(int index, const QPen &pen)
{
    QCPAxis *pAxis = this->axis(index);
    if(pAxis) {
        pAxis->grid()->setSubGridPen(pen);
    }
}

void PlotController::setSubGridVisible(int index, bool visible)
{
    QCPAxis *pAxis = this->axis(index);
    if(pAxis) {
        pAxis->grid()->setSubGridVisible(visible);
    }
}

void PlotController::setAxisLabel(int index, const QString &label)
{
    if(this->axis(index))
        this->axis(index)->setLabel(label);
}

void PlotController::setAxisLabelColor(int index, const QColor &color)
{
    if(this->axis(index))
        this->axis(index)->setLabelColor(color);
}

void PlotController::setAxisTickLabelVisible(int index, bool visible)
{
    if(this->axis(index))
        this->axis(index)->setTickLabels(visible);
}

void PlotController::setAxisTickLabelColor(int index, const QColor &color)
{
    if(this->axis(index))
        this->axis(index)->setTickLabelColor(color);
}

void PlotController::setAxisTickLabelSide(int index, QCPAxis::LabelSide side)
{
    if(this->axis(index))
        this->axis(index)->setTickLabelSide(side);
}

void PlotController::setAxisTickLabelRotation(int index, double rotation)
{
    if(this->axis(index))
        this->axis(index)->setTickLabelRotation(rotation);
}

void PlotController::setAxisRange(int index, double min, double max)
{
    if(this->axis(index))
        this->axis(index)->setRange(min, max);
}

void PlotController::setAxisPen(int index, const QPen &pen)
{
    if(this->axis(index))
        this->axis(index)->setBasePen(pen);
}

void PlotController::setAxisTickPen(int index, const QPen &pen)
{
    if(this->axis(index))
        this->axis(index)->setTickPen(pen);
}

void PlotController::setAxisSubTickPen(int index, const QPen &pen)
{
    if(this->axis(index))
        this->axis(index)->setSubTickPen(pen);
}

void PlotController::setAxisLowerEnding(int index, const QCPLineEnding &ending)
{
    if(axis(index))
        axis(index)->setLowerEnding(ending);
}

void PlotController::setAxisUpperEnding(int index, const QCPLineEnding & ending)
{
    if(this->axis(index))
        this->axis(index)->setUpperEnding(ending);
}

void PlotController::setLegendVisible(bool visible)
{
    m_plot->legend->setVisible(visible);
}

void PlotController::setSelectionRectPen(const QPen &pen)
{
    m_plot->selectionRect()->setPen(pen);
}

void PlotController::setSelectionRectBrush(const QBrush &brush)
{
    m_plot->selectionRect()->setBrush(brush);
}

void PlotController::setSelectionRectMode(const QCP::SelectionRectMode &mode)
{
    m_plot->setSelectionRectMode(mode);
}

void PlotController::setGraphName(int index, const QString &name)
{
    if(graph(index))
        graph(index)->setName(name);
}

void PlotController::setGraphPen(int index, const QPen &pen)
{
    if(graph(index))
        graph(index)->setPen(pen);
}

void PlotController::setGraphBrush(int index, const QBrush &brush)
{
    if(graph(index))
        graph(index)->setBrush(brush);
}

void PlotController::setGraphAntialiasedAll(int index, bool on)
{
    if(graph(index)) {
        graph(index)->setAntialiased(on);
        graph(index)->setAntialiasedFill(on);
        graph(index)->setAntialiasedScatters(on);
    }
}

void PlotController::setGraphChannelFillGraph(int mainIndex, int otherIndex)
{
    if(graph(mainIndex) && graph(otherIndex))
        graph(mainIndex)->setChannelFillGraph(graph(otherIndex));
}

void PlotController::setGraphLineStyle(int index, QCPGraph::LineStyle style)
{
    if(graph(index))
        graph(index)->setLineStyle(style);
}

void PlotController::setGraphScatterStyle(int index, QCPScatterStyle style)
{
    if(graph(index))
        graph(index)->setScatterStyle(style);
}

void PlotController::rescaleGraphAxes(int index, bool onlyEnlarge)
{
    if(graph(index))
        graph(index)->rescaleAxes(onlyEnlarge);
}

void PlotController::rescaleGraphKeyAxis(int index, bool onlyEnlarge)
{
    if(graph(index))
        graph(index)->rescaleKeyAxis(onlyEnlarge);
}

void PlotController::rescaleGraphValueAxis(int index, bool onlyEnlarge)
{
    if(graph(index))
        graph(index)->rescaleValueAxis(onlyEnlarge);
}

void PlotController::setAxisRectRangeZoomFactor(double x, double y)
{
    m_plot->axisRect()->setRangeZoomFactor(x, y);
}

void PlotController::setInteraction(const QCP::Interaction &interaction, bool enabled)
{
    m_plot->setInteraction(interaction, enabled);
}

void PlotController::setInteractions(const QCP::Interactions &interactions)
{
    m_plot->setInteractions(interactions);
}

void PlotController::setTracerEnabled(bool enabled)
{
    m_tracerEnabled = enabled;
}

QCPAxis *PlotController::axis(int index)
{
    if(index == 0)
        return m_plot->xAxis;
    else if(index == 1)
        return m_plot->yAxis;
    else if(index == 2)
        return m_plot->xAxis2;
    else if(index == 3)
        return m_plot->yAxis2;
    return nullptr;
}

void PlotController::setAxisVisible(int index, bool visible)
{
    if(this->axis(index))
        this->axis(index)->setVisible(visible);
}

void PlotController::setupFullAxesBox(bool connectRanges)
{
    m_plot->axisRect()->setupFullAxesBox(connectRanges);
}

void PlotController::setAxisConnectRanges(int index, bool connectRanges)
{
    QCPAxis *a1,*a2;
    if(index == 0)
    {
        a1 = m_plot->xAxis;
        a2 = m_plot->xAxis2;
    } else if(index == 1) {
        a1 = m_plot->yAxis;
        a2 = m_plot->yAxis2;
    } else
        return;

    if(connectRanges) {
        connect(a1, QOverload<const QCPRange &>::of(&QCPAxis::rangeChanged), a2, QOverload<const QCPRange &>::of(&QCPAxis::setRange));
    } else {
        disconnect(a1, QOverload<const QCPRange &>::of(&QCPAxis::rangeChanged), a2, QOverload<const QCPRange &>::of(&QCPAxis::setRange));

    }
}

QCPGraph *PlotController::graph(int index)
{
    if(index >= 0 && index < m_plot->graphCount()) {
        return m_plot->graph(index);
    }
    return nullptr;
}
